package com.by.redis.support;

import cn.hutool.core.lang.Pair;
import cn.hutool.core.lang.Snowflake;
import com.by.redis.enums.ByRedisUtilityEnum;
import com.by.toolkit.consts.GlobalConst;
import com.by.toolkit.consts.RedisConst;
import com.by.toolkit.utils.SplitterUtil;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

import static com.by.toolkit.utils.ExceptionUtil.getStackTrace;
import static com.by.toolkit.utils.ExceptionUtil.throwError;

@Slf4j
@Component
public class SnowflakeSupport {

    @Resource
    private ByRedisSupport byRedisSupport;

    @Resource
    private RedissonClient redissonClient;

    private static final ThreadLocal<AtomicInteger> THREAD_LOCAL_INTEGER = new ThreadLocal<>();

    private static final Snowflake SNOWFLAKE = new Snowflake(1, 31);

    public Long nextId(String snowflakeName) {

        long nextId = SNOWFLAKE.nextId();
        RLock clientLock = redissonClient.getLock(SplitterUtil.EN_DROP_JOIN.join(RedisConst.SNOWFLAKE_LOCK_KEY, snowflakeName));
        try {
            THREAD_LOCAL_INTEGER.set(new AtomicInteger(3));
            Boolean tryLock = clientLock.tryLock(1, 1, TimeUnit.SECONDS);
            if (!tryLock) {
                throwError("获取所失败");
            }
            StringRedisTemplate stringRedisTemplate = byRedisSupport.getStringRedisTemplate(ByRedisUtilityEnum.COMMON);
            String snowflakeKey = SplitterUtil.EN_DROP_JOIN.join(RedisConst.SNOWFLAKE_KEY, snowflakeName);
            String oldLastNextIdStr = stringRedisTemplate.opsForValue().get(snowflakeKey);
            Long oldLastNextId = StringUtils.isNotBlank(oldLastNextIdStr) ? Long.parseLong(oldLastNextIdStr) : GlobalConst.ZERO_LONG;
            if (oldLastNextId.compareTo(nextId) > 0) {
                if (THREAD_LOCAL_INTEGER.get().decrementAndGet() < 0) {
                    return null;
                }
                return nextId(snowflakeName);
            }
            stringRedisTemplate.opsForValue().set(snowflakeKey, String.valueOf(nextId));
            return nextId;
        } catch (InterruptedException e) {
            log.error("[SnowflakeSupport][nextId] 雪花算法生成id失败:{}", getStackTrace(e));

        } finally {
            THREAD_LOCAL_INTEGER.remove();
            if (clientLock.isHeldByCurrentThread()) {
                clientLock.unlock();
            }
        }
        return null;
    }

    /**
     * 根据时间戳获取终点
     *
     * @param timestamp
     * @return
     */
    public Long getIdScopeByTimestamp(long timestamp) {

        Pair<Long, Long> idScopeByTimestamp = SNOWFLAKE.getIdScopeByTimestamp(0L, timestamp, false);
        Long value = idScopeByTimestamp.getValue();
        return value;
    }

    public static class SnowflakeSupportConst {
        public static final String COURSE_WARE_EDIT_SYNC_CURRICULUM = "courseWareEditSyncCurriculum";
    }

}
